<?php
/**
 * CategoryRepo.php
 *
 * @copyright   2023 thingsworld.com.cn - All Rights Reserved
 * @link        http://thingsworld.com.cn/
 * @author      stiffer.chen <chenl@thingsworld.com.cn>
 * @created     2023-02-13 19:23:41
 * @modified    2023-02-13 19:23:41
 *
 */

namespace App\Repositories\Product;

use App\Models\Product\Category;
use Illuminate\Support\Facades\DB;

class CategoryRepo
{
    const CHILDREN = 'children';
    const PARENT = 'parent';

    private static $allCategories = null;

    public static function getList()
    {
        $perPage = (int)request('limit');
        if ($perPage < 1) {
            $perPage = 1;
        }

        $builder = Category::query();

        $name = trim(request()->get('name') ?? '');
        if ($name) {
            $builder->withName($name);
        }
        $status = trim(request()->get('status') ?? '');
        if ($status != '') {
            $status = (int)$status;
            if ($status) {
                $status = 1;
            }
            $builder->withStatus($status);
        }
        $result = $builder->paginate($perPage);
        // set pagination's item data
        $result->transform(function ($item) {
            $item->{self::CHILDREN} = self::childrenTree($item->id);
            $item->{self::PARENT} = self::parentTree($item->parent_id);
            return $item;
        });
        return $result;
    }

    /**
     * 获取分类树
     */
    public static function tree()
    {
        $all = self::all();
        $name = trim(request()->get('name') ?? '');
        $allCategories = [];
        foreach ($all as $item) {
            $itemId = $item['id'];
            $save = false;
            if (!$name) {
                $save = true;
            }
            if ($name && strrpos($item['name'], $name) !== false) {
                $save = true;
            }
            $allChildIds = self::getAllChildIds($itemId);
            foreach ($all as $temp) {
                if ($name && in_array($temp['id'], $allChildIds) && strrpos($temp['name'], $name) !== false) {
                    $save = true;
                    break;
                }
            }
            if (!$save) {
                continue;
            }
            $allCategories[] = $item;
        }
        $allCategories = array_values($allCategories);
        $topCategories = collect($allCategories)->filter(function($item) {
            return $item['parent_id'] == 0;
        })->toArray();
        if (!$topCategories) {
            return [];
        }
        $results = [];
        foreach ($topCategories as $category) {
            $categoryId = $category['id'];
            $children = self::childrenTree($categoryId);
            $parent = self::parentTree($category['parent_id']);
            $category['children'] = $children;
            $category['parent'] = $parent;
            $results[] = $category;
        }
        return $results;
    }

    public static function store($id)
    {
        $categoryData = self::requestData($id);
        if ($id) {
            $category = Category::find($id);
        } else {
            $category = new Category();
        }
        if (empty($category)) {
            $category = new Category();
        }

        $category->fill($categoryData);
        $category->saveOrFail();
        return self::fetch($category->id);
    }

    public static function fetch($id)
    {
        $category = Category::find($id);
        if (empty($category)) {
            throw new \Exception('产品分类不存在');
        }
        $category = $category->toArray();
        $category[self::CHILDREN] = self::childrenTree($category['id']);
        $category[self::PARENT] = self::parentTree($category['parent_id']);
        return $category;
    }

    private static function all()
    {
        if (!is_null(self::$allCategories)) {
            return self::$allCategories;
        }
        self::$allCategories = Category::all()->keyBy('id')->toArray();
        return self::$allCategories;
    }

    public static function destroy($id)
    {
        $category = Category::find($id);
        if (empty($category)) {
            throw new \Exception('产品分类不存在');
        }
        $subCategoryIds = self::getAllChildIds($id);
        if ($subCategoryIds) {
            Category::query()
                ->whereIn('id', $subCategoryIds)
                ->delete();
        }
        $category->delete();
    }

    private static function parentTree($parentId)
    {
        $tree = [];
        $allCategories = self::all();
        foreach ($allCategories as $item) {
            $tree[$item['parent_id']] = $item;
        }
        foreach ($tree as $item) {
            $tree[$item['id']][self::PARENT][] = &$tree[$item['parent_id']];
        }

        return $tree[$parentId][self::PARENT] ?? [];
    }

    private static function requestData($id)
    {
        $categoryData = request()->getContent();
        $categoryArr = json_decode($categoryData, true);

        $status = $categoryArr['status'] ?? '';
        $dbStatus = 0;
        if ($status !== '') {
            $status = (int)$status;
            if ($status) {
                $dbStatus = 1;
            }
        }
        $parentId = intval($categoryArr['parent_id'] ?? 0);
        if ($id) {
            if ($parentId == $id) {
                throw new \Exception('父级分类设置错误');
            }
            $childIds = self::getAllChildIds($id);
            if ($parentId && $childIds && in_array($parentId, $childIds)) {
                throw new \Exception('父级分类设置错误');
            }
        }

        $name = trim($categoryArr['name'] ?? '');
        if (!$name) {
            throw new \Exception('名称设置错误');
        }
        $sortOrder = intval($categoryArr['sort_order'] ?? 0);

        return [
            'parent_id' => $parentId,
            'name' => $name,
            'sort_order' => $sortOrder,
            'status' => $dbStatus
        ];
    }

    private static function childrenTree($categoryId)
    {
        $tree = [];
        $allCategories = self::all();
        foreach ($allCategories as $item) {
            $tree[$item['id']] = $item;
        }

        foreach ($tree as $item) {
            $tree[$item['parent_id']][self::CHILDREN][] = &$tree[$item['id']];
        }
        return $tree[$categoryId][self::CHILDREN] ?? [];
    }

    private static function getAllChildIds($id, &$childIds = [])
    {
        if (!$id) {
            return [];
        }
        $allCategories = self::all();
        foreach ($allCategories as $categoryId => $category) {
            if ($id == $category['parent_id']) {
                $childIds[] = $categoryId;
                unset($allCategories[$categoryId]);
                self::getAllChildIds($categoryId, $childIds);
            }
        }
        return $childIds;
    }
}